home *** CD-ROM | disk | FTP | other *** search
- ;----------------------------------------------------------------------
- ; RUN.ASM
- ; Format: RUN [/C][/S][d:][directory] filename [arguments]
- ; /C = Change to the directory and run
- ; /S = Stay in current directory and run
- ; Default is /S
- ;----------------------------------------------------------------------
- CODE SEGMENT ;********************************;
- ASSUME CS:CODE,DS:CODE ;* *;
- ORG 100H ;* Requires MASM 2.0 or later *;
- ;* Remember to EXE2BIN *;
- START: JMP BEGINNING ;* *;
- ;********************************;
-
- ; DATA AREA
- ; ---------
- COPYRIGHT DB "RUN 1.0 (c) 1987 Ziff Communications Co.",13,10
- DB "PC Magazine ",254," Michael J. Mefford",13,10,"$",26
-
- CURRENT_DISK DB ?
- WORKING_DISK DB 0FFH
- FILE_START DW ?
- FILENAME_END DW ?
- ARGUMENTS DW ?
- PATH_END DW 0
- CHANGE_FLAG DB 0
- BAT_FLAG DB 0
-
- SYNTAX DB 13,10,"Syntax: RUN [/C][/S][d:][directory] filename [arguments]"
- DB 13,10,"/C = Change to the directory and run"
- DB 13,10,"/S = Stay in current directory and run"
- DB 13,10,"Default is /S"
- CR_LF DB 13,10,"$"
-
- FAIL DB 13,10,"Can't find $"
- SEARCHING DB 13,10,"Searching for $"
- DELIMITERS DB 9,13,32,"/<>."
- EXE DB "EXE",0
- COM DB "COM",0
- BAT DB "BAT",0
- ROOT DB "\",0
- STAR_DOT_STAR DB "*.*",0
- PARENT DB "..",0
- COPY DB " /C "
- COMSPEC DB "COMSPEC="
-
- STACK_SEG DW ?
- STACK_PTR DW ?
-
- PARAMETER_BLOCK LABEL WORD
-
- ENVIRONMENT DW 0
- COM_LINE_PTR DW PARAMETER,?
- FCB_1ST DW FCB_5CH, ?
- FCB_2ND DW FCB_6CH, ?
-
- ;----------------------------------------------------------------------------;
- ; Some housekeeping first. Since we will be changing the default drive ;
- ; and directory to the requested drive and directory, we need to save the ;
- ; current defaults, so they can be restored. Change the default DTA. ;
- ; Move the stack and deallocate memory so we have room to spawn the program. ;
- ;----------------------------------------------------------------------------;
-
- ; CODE AREA
- ; ---------
- BEGINNING:
- MOV AH,9
- MOV DX,OFFSET COPYRIGHT
- INT 21H
-
- CLD ;String moves forward.
- CALL GET_DRIVE ;Get current drive.
- MOV CURRENT_DISK,AL ;Save.
- MOV SI,OFFSET CURRENT_DIR ;Get current directory.
- CALL GET_DIR
-
- MOV DX,OFFSET DTA ;Move the disk transfer address
- MOV AH,1AH ; to the end of code to protect
- INT 21H ; command line parameters at 80h.
-
- MOV SP,OFFSET CODE_END ;Move the stack down to the
- MOV BX,SP ; end of code segment.
- ADD BX,15 ;Round up paragraph size.
- MOV CL,4
- SHR BX,CL
- MOV AH,4AH ;Deallocate rest of memory.
- INT 21H
-
- ;--------------------------------------------------;
- ; Parse the command line parameters. Start by ;
- ; scanning off spaces and RUN's switch characters. ;
- ;--------------------------------------------------;
-
- MOV SI,80H ;Point to command line parameters.
- LODSB
- CMP AL,0 ;Are there any?
- JZ BAD_SYNTAX ;If no, exit.
-
- NEXT_LEADING: LODSB ;Get a byte.
- CMP AL,"/" ;Is it a switch character?
- JNZ CK_CR ;If no, check if end.
- LODSB ;Else, get switch character.
- CMP AL,13 ;Make sure not end.
- JZ BAD_SYNTAX
- AND AL,5FH ;Capitalize.
- CMP AL,"C" ;Is it "C"?
- JNZ CK_NOCHANGE
- MOV CHANGE_FLAG,1 ;If yes, indicate to change dir.
- CK_NOCHANGE: CMP AL,"S" ;Else, is it "S"?
- JNZ NEXT_LEADING ;If no, next leading character.
- MOV CHANGE_FLAG,0 ;Else, indicate not to change dir.
- JMP SHORT NEXT_LEADING
-
- CK_CR: CMP AL,13 ;Is it carriage return?
- JNZ CK_LEADING ;If yes, bad syntax.
- BAD_SYNTAX: JMP SYNTAX_EXIT
- CK_LEADING: CMP AL,32 ;Is it a space or tab?
- JBE NEXT_LEADING ;If yes, get next character.
- DEC SI ;Else, adjust pointer back one.
- PUSH SI ;Save as possible path request.
- MOV FILE_START,SI ;Save as possible start of filename
-
- ;----------------------------------------------------;
- ; We now have the start of the run file. Next scan ;
- ; to the end of filename looking for a path request. ;
- ;----------------------------------------------------;
-
- NEXT_PATH: LODSB ;Get a byte.
- CMP AL,":" ;Drive request?
- JNZ CK_PATH ;If no, check if directory.
- MOV DL,[SI-2] ;Else, retrieve drive.
- AND DL,5FH ;Capitalize.
- SUB DL,"A" ;Convert to DOS format.
- CALL CHANGE_DRIVE ;Change drive.
- MOV FILE_START,SI ;Save as possible start of filename
- JMP SHORT NEXT_PATH
-
- CK_PATH: CMP AL,"\" ;Is it a path delimiter?
- JNZ CK_DELIMITER ;If no, see if end of filename.
- MOV PATH_END,SI ;Else, save as path end.
- MOV FILE_START,SI ;Save as possible start of filename
- CK_DELIMITER: MOV DI,OFFSET DELIMITERS ;Check for tab, carriage return,
- MOV CX,6 ; space, switch, or redirection
- REPNZ SCASB ; characters as filename end.
- JNZ NEXT_PATH ;Continue until found.
-
- DEC SI ;Else, adjust pointer back one.
- MOV ARGUMENTS,SI ;Save as start of arguments.
-
- ;--------------------------------------------------;
- ; Parse the arguments for two file control blocks. ;
- ;--------------------------------------------------;
-
- MOV DI,OFFSET FCB_5CH ;Point to first FCB storage.
- MOV AX,2901H ;Parse and scan off leading
- INT 21H ; separators.
- MOV DI,OFFSET FCB_6CH ;Same for second FCB.
- MOV AX,2901H
- INT 21H
-
- ;----------------------------------------------------;
- ; Store working path so can be restored on exit. ;
- ; Store run filename stripping extension in process. ;
- ;----------------------------------------------------;
-
- CALL GET_DRIVE ;Store working drive.
- MOV WORKING_DISK,AL
- MOV SI,OFFSET WORKING_DIR ;Store working directory.
- CALL GET_DIR
-
- MOV SI,FILE_START ;Store the run filename.
- MOV DI,OFFSET FILENAME
- NEXT_FILENAME: LODSB ;Get a byte.
- PUSH DI
- MOV DI,OFFSET DELIMITERS ;Are we at the end of filename
- MOV CX,7 ; or encountered dot?
- REPNZ SCASB
- POP DI
- JZ STORE_DOT ;If yes, done here.
- STOSB
- JMP SHORT NEXT_FILENAME
-
- STORE_DOT: MOV AL,"."
- STOSB
- MOV FILENAME_END,DI ;Store end of filename.
-
- ;---------------------------------------------------------;
- ; If a path was found, change directory and search for ;
- ; run file. Else, do a diskwide search for the run file. ;
- ;---------------------------------------------------------;
-
- POP DX ;Retrieve filespec start.
- MOV SI,PATH_END ;Did we find a path?
- CMP SI,0
- JZ GLOBAL ;If no, do global search.
- CMP BYTE PTR [SI-2],":" ;Else, check if special
- JZ CHANGE_IT ; case of root directory.
- CMP BYTE PTR [SI-2],32
- JBE CHANGE_IT ;If yes, change directory.
- DEC SI ;If no, adjust pointer.
- CHANGE_IT: PUSH [SI] ;Save path end.
- MOV BYTE PTR [SI],0 ;Convert to ASCIIZ for DOS.
- CALL CHANGE_DIR ;Change directory.
- POP [SI] ;Restore path end.
-
- CALL CK_EXECUTABLE ;Search current directory
- JNC RUN_IT ; for filename; run it if found.
- JMP SHORT ERROR_EXIT ;Else, exit with message.
-
- GLOBAL: CALL GLOBAL_SEARCH ;If no directory request, do a
- JC ERROR_EXIT ; diskwide search for filename.
- RUN_IT: CALL EXEC ;If found, execute it.
- JMP SHORT EXIT
-
- ;-----------------------------------------------------------------------;
- ; This is the exit routine. Restore the defaults the way we found them. ;
- ;-----------------------------------------------------------------------;
-
- ERROR_EXIT: MOV DX,OFFSET FAIL ;Display "Can't find ".
- CALL PRINT_STRING
- CALL PRINT_NAME ;Display filename.
- SYNTAX_EXIT: MOV DX,OFFSET SYNTAX ;Display RUN syntax.
- CALL PRINT_STRING
- MOV AL,1 ;Error code of one.
- JMP SHORT TERMINATE
-
- EXIT: XOR AL,AL ;Error code of zero.
- TERMINATE: PUSH AX ;Save error code.
- CALL RESTORE_PATH ;Restore defaults.
- POP AX ;Retrieve error code.
- MOV AH,4CH ;Exit.
- INT 21H
-
- ;***************;
- ;* SUBROUTINES *;
- ;***************;
-
- ;-----------------------------------------------------------------;
- ; This subroutine adds the extension COM, EXE and BAT ;
- ; (in that order) to the filename and checks to see if it exists. ;
- ;-----------------------------------------------------------------;
-
- CK_EXECUTABLE: MOV DX,OFFSET FILENAME ;Point to filename.
- MOV BX,FILENAME_END ;Point to filename end.
- MOV SI,OFFSET COM ;Check for .COM
- CALL FIND_MATCH
- JNC CK_END
- MOV SI,OFFSET EXE ;Check for .EXE
- CALL FIND_MATCH
- JNC CK_END
- MOV SI,OFFSET BAT ;Check for .BAT
- CALL FIND_MATCH
- JC CK_END
- MOV BAT_FLAG,1 ;If batch file, indicate so.
- CK_END: RET
-
- ;---------------------------;
-
- FIND_MATCH: MOV DI,BX ;Add extension to filename.
- MOVSW
- MOVSW
- MOV CX,7
- CALL FIND_FIRST ;See if it exists.
- RET
-
- ;-----------------------------------------------------------------;
- ; This subroutine executes the file. If it's a batch file, load ;
- ; secondary copy of COMMAND.COM. Else, let 4Bh execute the file. ;
- ;-----------------------------------------------------------------;
-
- EXEC: PUSH DS ;Save segment registers.
- PUSH ES
- CLI
- MOV STACK_SEG,SS ;Save stack segment and pointer.
- MOV STACK_PTR,SP
- STI
-
- MOV COM_LINE_PTR + 2,DS ;Point to command line.
- MOV FCB_1ST + 2,DS ;Point to file control blocks.
- MOV FCB_2ND + 2,DS
-
- CMP BAT_FLAG,1 ;Is it a batch file?
- JNZ EXECUTE ;If no, just execute file.
- MOV SI,OFFSET COPY ;Else, let COMMAND.COM/C run it.
- MOV DI,OFFSET PARAMETER + 1 ;Construct parameter.
- MOVSW
- MOVSW
- CALL MAKE_FILESPEC ;Add filespec.
- DEC DI
- CALL ADD_PARAMETER ;Add arguments.
-
- MOV AX,DS:[2CH] ;Retrieve environment segment.
- MOV DS,AX
- XOR AX,AX
-
- FIND_COMSPEC: MOV SI,AX ;Search for "COMSPEC=".
- INC AX
- MOV DI,OFFSET COMSPEC
- MOV CX,4
- REPZ CMPSW
- JNZ FIND_COMSPEC
- MOV DX,SI ;What follows is COMMAND.COM path.
- JMP SHORT EXEC_FILE ;Ready to execute.
-
- EXECUTE: MOV DI,OFFSET FILESPEC ;Construct filespec.
- CALL MAKE_FILESPEC
- MOV DI,OFFSET PARAMETER + 1 ;Construct arguments.
- CALL ADD_PARAMETER
- MOV DX,OFFSET FILESPEC
-
- EXEC_FILE: MOV BX,OFFSET PARAMETER_BLOCK ;Point to parameter block.
- MOV AX,4B00H ;Execute.
- INT 21H
-
- CLI
- MOV SP,CS:STACK_PTR ;Restore stack segment and pointer.
- MOV SS,CS:STACK_SEG
- STI
- POP ES ;Restore segment registers.
- POP DS
- RET
-
- ;---------------------------;
-
- MAKE_FILESPEC: CMP CHANGE_FLAG,1 ;Are we to change directory?
- JZ ADD_FILENAME ;If yes, execute filename.
- MOV AL,WORKING_DISK ;Else, add working drive.
- ADD AL,"A"
- STOSB
- MOV AL,":"
- STOSB
- MOV SI,DI ;Add working directory.
- CALL GET_DIR
- CALL RESTORE_PATH ;Restore default path.
- MOV DI,SI
- CMP BYTE PTR [DI],0 ;If root, ready for filename.
- JZ ADD_FILENAME
- FIND_END: INC DI ;Else, find end of path.
- CMP BYTE PTR [DI],0
- JNZ FIND_END
- MOV AL,"\" ;Tack on "\" path delimiter.
- STOSB
- ADD_FILENAME: MOV SI,OFFSET FILENAME ;Add on filename.
- NEXT_NAME: LODSB
- STOSB
- CMP AL,0
- JNZ NEXT_NAME
- RET
-
- ;---------------------------;
-
- ADD_PARAMETER: MOV SI,ARGUMENTS ;Add on arguments.
- GET_PARAMETER: LODSB
- STOSB
- CMP AL,13
- JNZ GET_PARAMETER
- XOR CL,CL ;Zero in counter.
- MOV SI,OFFSET PARAMETER + 1
- CNT_PARAMETER: LODSB
- CMP AL,13
- JZ END_PARAMETER
- INC CL ;Count parameter length.
- JMP SHORT CNT_PARAMETER
- END_PARAMETER: MOV PARAMETER,CL ;Store as first byte of parameter.
- RET
-
- ;---------------------------------------------;
- ; This subroutine restores the default paths. ;
- ;---------------------------------------------;
-
- RESTORE_PATH: CMP WORKING_DISK,0FFH ;Did we get defaults?
- JZ END_RESTORE ;If no, done here.
- MOV DX,OFFSET WORKING_DIR
- CALL CHANGE_DIR
- MOV DL,CURRENT_DISK
- CALL CHANGE_DRIVE
- MOV DX,OFFSET CURRENT_DIR
- CALL CHANGE_DIR
- END_RESTORE: RET
-
- ;----------------------------------------;
- ; These are the DOS support subroutines. ;
- ;----------------------------------------;
-
- PRINT_NAME: MOV SI,OFFSET FILENAME ;Print filename
- NEXT_PRINT: LODSB
- CMP AL,"."
- JZ END_NAME
- MOV DL,AL
- MOV AH,2 ; via DOS Display Output.
- INT 21H
- JMP SHORT NEXT_PRINT
- END_NAME: MOV DX,OFFSET CR_LF ;Print carriage return linefeed.
- CALL PRINT_STRING
- RET
-
- GET_DRIVE: MOV AH,19H
- JMP SHORT DOS_CALL
-
- CHANGE_DRIVE: MOV AH,0EH
- JMP SHORT DOS_CALL
-
- FIND_FIRST: MOV AH,4EH
- JMP SHORT DOS_CALL
-
- FIND_NEXT: MOV AH,4FH
- JMP SHORT DOS_CALL
-
- GET_DIR: MOV BYTE PTR [SI],"\" ;DOS doesn't preface directory
- INC SI ; with slash so we must.
- XOR DL,DL
- MOV AH,47H ;Retrieve default directory.
- JMP SHORT DOS_CALL
-
- CHANGE_DIR: MOV AH,3BH
- JMP SHORT DOS_CALL
-
- PRINT_STRING: MOV AH,9
- JMP SHORT DOS_CALL
-
- CK_KEY: MOV AH,0BH
-
- ;---------------------------;
-
- DOS_CALL: INT 21H
- RET
-
- ;---------------------------------------------------------------;
- ; This subroutine will systematically change directories up and ;
- ; down the directory tree, searching for the matching filename. ;
- ;---------------------------------------------------------------;
-
- GLOBAL_SEARCH: MOV DX,OFFSET SEARCHING ;Display searching message.
- CALL PRINT_STRING
- CALL PRINT_NAME ;Display filename.
- MOV DX,OFFSET ROOT ;Start the search from root.
- CALL CHANGE_DIR
- MOV DI,OFFSET DIR_LEVEL
- MOV BP,DI ;Point to first level directory.
- MOV AX,0101H ;Store initial level of one.
- MOV CX,64 / 2
- REP STOSW
-
- FIRST_FILE: CALL CK_KEY ;Was a key pressed?
- CMP AL,0
- JNZ END_SEARCHING ;If yes, abort search.
- CALL CK_EXECUTABLE ;Check if matching executable.
- JC FIRST_DIR ;If no, try next directory.
- RET ;Else, return to execute.
-
- PARENT_DIR: CMP BP,OFFSET DIR_LEVEL ;When we try to return to parent
- JNZ CONTINUE ; directory and are in root, we
- END_SEARCHING: STC ; are done.
- RET
-
- CONTINUE: MOV DX,OFFSET PARENT ;Otherwise, change
- CALL CHANGE_DIR ; to parent directory.
- MOV BYTE PTR DS:[BP],1 ;Put one back in previous level
- DEC BP ; and point to parent level.
-
- FIRST_DIR: XOR BL,BL ;Use BL as pointer to directory no.
- MOV DX,OFFSET STAR_DOT_STAR
- MOV CX,10H ;Ask for directory match.
- CALL FIND_FIRST ;Find first matching.
- JC PARENT_DIR
- CK_DIR: CMP BYTE PTR DS:[DTA+21],10H ;If not a directory, get next.
- JNZ NEXT_DIR
- CMP BYTE PTR DS:[DTA+30],'.' ;If dot directory, get next.
- JZ NEXT_DIR
- INC BL ;Increment position in directory.
- CMP BL,DS:[BP] ;Continue until new directory.
- JNZ NEXT_DIR
- INC BYTE PTR DS:[BP] ;Update variables.
- MOV DX,OFFSET DTA + 30
- CALL CHANGE_DIR ;Change the directory.
- INC BP
- JMP SHORT FIRST_FILE ;See if directory has a run file.
-
- NEXT_DIR: CALL FIND_NEXT ;Get all subdirectories in current
- JC PARENT_DIR ; directory then go to parent.
- JMP SHORT CK_DIR
-
- ;---------------------------;
-
- PARAMETER LABEL BYTE
- FCB_5CH EQU PARAMETER + 256
- FCB_6CH EQU FCB_5CH + 16
- CURRENT_DIR EQU FCB_6CH + 16
- WORKING_DIR EQU CURRENT_DIR + 65
- DIR_LEVEL EQU WORKING_DIR + 65
- FILENAME EQU DIR_LEVEL + 64
- FILESPEC EQU FILENAME + 13
- DTA EQU FILESPEC + 67 + 13
- CODE_END EQU DTA + 43 + 256
-
- CODE ENDS
- END START